昨天有說明到函式與建構式的原型,及指定建構式函式原型為另一個建構式函式,但其實這會造成覆寫 constructor 的問題。
我們昨天有提到「建構式函式可以透過 .constructor 來存取建立物件的函式以此來作類型檢查。」,但是這個例子卻會導致 trickyMan 的建構式的原型被覆寫,無法去判斷。
function Person(){};
Person.prototype.say = "Hi";
function trickyMan(){};
trickyMan.prototype = new Person();
var Jason = new trickyMan();
trickyMan.constructor === trickyMan;//false
所以如果在 Jason 物件上呼叫 .constructor ,會無法找到直到在 Person 上找到參照 Person 函式的 constructor 。
但是,這事實上是錯誤的,如果我問是哪個函式建立了 Jason 物件,會得到 Person 這可能會產生一些 Bug。
幸好在 JS 中,物件的每個屬性都有一個屬性描述子( property desciptor ),可以夠過它設定以下鍵值:
for-in 迴圈操作中出現先來個簡單的例子:
Jason.age = 29;
age 這個屬性會是 可設定、可列舉並且可寫入的,它的值被設為 29, get 和 set 函式則會是 undefined 。
如果要對上述設定值做更動的話,可以用 Object.defineProperty:
var Jason = {};
Jason.say = "R~";
Object.defineProperty(Jason,"age",{
configurable : false,
enumerable : false,
value : 29,
writable : true
});
console.log("age" in Jason);
for(let key in Jason){
console.log(key);
}
好,現在我知道有這東西了,但這跟一開始說的 constructor 有關係嗎?
當然有!我們試著用 trickyMan 擴展( extend )Person 時(也可以說是讓 trickyMan 成為 Person 的子類別),就失去原本保存在 constructor 屬性上的 trickyMan 原型。
我們可以用 Object.defineProperty 在新的 trickyMan.prototype 上定義一個新的 constructor 屬性。
function Person(){};
Person.prototype.say = "Hi";
function trickyMan(){};
trickyMan.prototype = new Person();
Object.defineProperty(trickyMan,"constructor",{
enumerable : false,
value : trickyMan,
writable : true
});
var Jason = new trickyMan();
trickyMan.constructor === trickyMan;//true
那麼,今天就到這邊,一樣如果有錯誤及來源未附上也歡迎留言指正,那麼我們明天見。
參考資料:
忍者 JavaScript 開發技巧探秘
你所不知道的 JS
Javascripter 必須知道的繼承 prototype,[[prototype]],proto
該來理解 JavaScript 的原型鍊了
proto VS. prototype in JavaScript